package ray_tracer;

import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;

import ray.CameraRay;
import screen.ScreenBuffer;

import util.Point3D;

public class Camera {

	public static final Point3D EYE = new Point3D(0.0f, 0.0f, 1.35f);

	private static final float SHIFT = 0.002f;
	private static final Rectangle2D VIEWPLANE = new Rectangle2D.Float(-0.75f,
			0.5625f, 1.5f, 1.125f);
	public static final Rectangle2D SHIFT_RIGHT = new Rectangle2D.Float(SHIFT,
			0.0f, 0.0f, 0.0f);
	public static final Rectangle2D SHIFT_LEFT = new Rectangle2D.Float(SHIFT
			* -1, 0.0f, 0.0f, 0.0f);
	public static final Rectangle2D SHIFT_UP = new Rectangle2D.Float(0.0f,
			SHIFT, 0.0f, 0.0f);
	public static final Rectangle2D SHIFT_DOWN = new Rectangle2D.Float(0.0f,
			SHIFT * -1, 0.0f, 0.0f);
	public static final Rectangle2D NO_SHIFT = new Rectangle2D.Float(0.0f,
			0.0f, 0.0f, 0.0f);

	private int currentX, currentY;
	private float screenWidth, screenHeight;
	private Rectangle2D currentShift;

	public Camera() {
		this.reset();
		this.currentShift = Camera.NO_SHIFT;
		this.screenWidth = (float) ScreenBuffer.SCREEN.getWidth();
		this.screenHeight = (float) ScreenBuffer.SCREEN.getHeight();
	}

	public void reset() {
		this.currentX = this.currentY = 0;
	}

	public CameraRay getNextCameraRay() {
		// find ray from eye
		Rectangle2D shiftedViewplane = new Rectangle2D.Double(Camera.VIEWPLANE
				.getX()
				+ this.currentShift.getX(), Camera.VIEWPLANE.getY()
				+ this.currentShift.getY(), Camera.VIEWPLANE.getWidth()
				+ this.currentShift.getWidth(), Camera.VIEWPLANE.getHeight()
				+ this.currentShift.getHeight());
		Point3D viewplanePoint = new Point3D(
				(float) shiftedViewplane.getX()
						+ (float) ((shiftedViewplane.getWidth() * currentX) / screenWidth),
				(float) shiftedViewplane.getY()
						- (float) ((shiftedViewplane.getHeight() * currentY) / screenHeight),
				Camera.EYE.getZ() - 1.0f);
		CameraRay cameraRay = new CameraRay(Camera.EYE, viewplanePoint,
				new Point2D.Float(currentX, currentY), false);
		// increment
		this.currentY++;
		if (this.currentY >= screenHeight) {
			this.currentX++;
			this.currentY = 0;
		}
		// return ray
		return cameraRay;
	}

	public boolean hasNextCameraRay() {
		return this.currentX < screenWidth;
	}

	public void setShift(Rectangle2D shift) {
		this.currentShift = shift;
	}

}
